package com.welson.db.cryptor.strategy;

import com.welson.db.cryptor.config.DbCryptorProperties;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import java.security.Security;

/**
 * SM4加解密策略实现
 * @author welson
 */
@Component
public class SM4CryptStrategy extends AbstractCryptStrategy {
    private static final String ALGORITHM = "SM4";

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public SM4CryptStrategy(DbCryptorProperties properties) {
        super(properties, ALGORITHM);
    }

    @Override
    public Cipher getCipher(String transformation) throws Exception {
        return Cipher.getInstance(transformation, BouncyCastleProvider.PROVIDER_NAME);
    }

    @Override
    public void validateMode(String mode) {
        if ("GCM".equals(mode)) {
            throw new IllegalArgumentException("SM4算法不支持GCM模式");
        }
    }

    @Override
    public byte[] encrypt(byte[] data, byte[] key, byte[] iv) throws Exception {
        String mode = getCurrentMode();
        validateMode(mode);
        
        String transformation = getTransformation();
        Cipher cipher = getCipher(transformation);
        javax.crypto.spec.SecretKeySpec secretKeySpec = new javax.crypto.spec.SecretKeySpec(key, ALGORITHM);
        
        if (isModeRequireIv(mode)) {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        } else {
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        }
        
        return cipher.doFinal(data);
    }

    @Override
    public byte[] decrypt(byte[] data, byte[] key, byte[] iv) throws Exception {
        String mode = getCurrentMode();
        validateMode(mode);
        
        String transformation = getTransformation();
        Cipher cipher = getCipher(transformation);
        javax.crypto.spec.SecretKeySpec secretKeySpec = new javax.crypto.spec.SecretKeySpec(key, ALGORITHM);
        
        if (isModeRequireIv(mode)) {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        } else {
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        }
        
        return cipher.doFinal(data);
    }

} 